package net.kelissa.jenetic.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import net.kelissa.jenetic.Organism;
import net.kelissa.jenetic.Population;
import net.kelissa.jenetic.RandomUtil;

public class PopulationBase implements Population
{
  private Organism best;

  private List<Organism> population;

  private int cullPopulation = 256;

  private int maxAge = 32;

  //----------------------------------
  public PopulationBase(Organism best)
  {
    this.best = best;
    this.population = new ArrayList<Organism>();
    this.population.add(best);
    for (int i = 0; i < this.cullPopulation; i++)
    {
      Organism clone = best.clone();
      clone.mutate();
      this.population.add(clone);
    }
  }

  /* (non-Javadoc)
   * @see net.kelissa.jenetic.Population#evolve()
   */
  public void evolve()
  {
    evolve(1);
  }

  /* (non-Javadoc)
   * @see net.kelissa.jenetic.Population#evolve(int)
   */
  public void evolve(int n)
  {
    for (int i = 0; i < n; i++)
    {
      createChildren();
      lifeAndDeath();
      cullPopulation();

    }
  }

  private void createChildren()
  {
    List<Organism> newPopulation = new ArrayList<Organism>();
    for (int i=0; i<this.cullPopulation; i++ )
    {
      Organism parent = RandomUtil.getX2Random(this.population);
      Organism parent1 = RandomUtil.getX2Random(this.population);
      newPopulation.add(parent1.conceive(parent));
    }
    this.population.addAll(newPopulation);
  }

  private void lifeAndDeath()
  {
    List<Organism> newPopulation = new ArrayList<Organism>();
    for (Organism chromosome : this.population)
    {
      chromosome.age();
      if (chromosome.getAge() < this.maxAge)
      {
        newPopulation.add(chromosome);
      }
    }
    this.population = newPopulation;
  }

  private void cullPopulation()
  {
    Collections.sort(this.population, this.best);
    this.population = this.population.subList(0, this.cullPopulation);
    Organism tmpBest = this.population.get(0);
    double tmpFitness = tmpBest.fitness();
    if (tmpFitness > best.fitness())
    {
      this.best = tmpBest;
      System.err.println("Eureka:" + tmpFitness);
    }
  }


  // -----------------------------------------------------
  /* (non-Javadoc)
   * @see net.kelissa.jenetic.Population#getBest()
   */
  public Organism getBest()
  {
    return this.best;
  }

  /* (non-Javadoc)
   * @see net.kelissa.jenetic.Population#getPopulation()
   */
  public List<Organism> getPopulation()
  {
    return this.population;
  }

  /* (non-Javadoc)
   * @see net.kelissa.jenetic.Population#getCullPopulation()
   */
  public int getCullPopulation()
  {
    return cullPopulation;
  }

  /* (non-Javadoc)
   * @see net.kelissa.jenetic.Population#setCullPopulation(int)
   */
  public void setCullPopulation(int cullPopulation)
  {
    this.cullPopulation = cullPopulation;
  }

  /* (non-Javadoc)
   * @see net.kelissa.jenetic.Population#getMaxAge()
   */
  public int getMaxAge()
  {
    return maxAge;
  }

  /* (non-Javadoc)
   * @see net.kelissa.jenetic.Population#setMaxAge(int)
   */
  public void setMaxAge(int maxAge)
  {
    this.maxAge = maxAge;
  }


}
